package com.noovo.comport.serial;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidParameterException;

import android.text.TextUtils;
import android_serialport_api.SerialPort;

public abstract class SerialHelper {
	private SerialPort mSerialPort;
	private OutputStream mOutputStream;
	private InputStream mInputStream;
	private ReadThread mReadThread;
	private SendThread mSendThread;
	private String sPort = "/dev/ttyS3";
	private int iBaudRate = 115200;
	private boolean _isOpen = false;
	private byte[] _bLoopData = new byte[] { 0x30 };
	private byte[] combinBuffer;
	private int iDelay = 1000;
	private boolean isLoopChecked = false;
	private boolean needRead = true;
	private boolean needWrite = true;
	private volatile int iReadWait = 50;//100
	private int databits = 8;
	private int stopbits = 1;
	private char parity = 'n';
	private int setdata = 0;

	// ----------------------------------------------------
	public SerialHelper(String sPort, int iBaudRate) {
		this.sPort = sPort;
		this.iBaudRate = iBaudRate;
	}

	public SerialHelper(String sPort, String sBaudRate) {
		this(sPort, Integer.parseInt(sBaudRate));
	}

	public SerialHelper(String sPort, int iBaudRate, boolean needRead, boolean needWrite) {
		this.sPort = sPort;
		this.iBaudRate = iBaudRate;
		this.needRead = needRead;
		this.needWrite = needWrite;
	}
	
	public void setOpt(int databits, int stopbits, char parity){
		this.databits = databits;
		this.stopbits = stopbits;
		this.parity = parity;
		setdata = 1;
	}
	
	// ----------------------------------------------------
	public void open() throws SecurityException, IOException, InvalidParameterException {
		mSerialPort = new SerialPort(new File(sPort), iBaudRate, 0, databits, stopbits, parity, setdata);
		mOutputStream = mSerialPort.getOutputStream();
		mInputStream = mSerialPort.getInputStream();
		if (needRead) {
			mReadThread = new ReadThread();
			mReadThread.start();
		}
		if (needWrite) {
			mSendThread = new SendThread();
			mSendThread.setSuspendFlag();
			mSendThread.start();
		}
		_isOpen = true;
	}

	// ----------------------------------------------------
	public void close() {
		if (mReadThread != null)
			mReadThread.interrupt();

		if (mSendThread != null)
			mSendThread.interrupt();

		if (mSerialPort != null) {
			mSerialPort.closeSerial();
			mSerialPort = null;
		}
		_isOpen = false;
	}

	// ----------------------------------------------------
	public void send(byte[] bOutArray) {
		try {
			mOutputStream.write(bOutArray);
			onDataSend(bOutArray);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	// ----------------------------------------------------
	public void sendHex(String sHex) {
		byte[] bOutArray = MyFunc.HexToByteArr(sHex);
		send(bOutArray);
	}

	// ----------------------------------------------------
	public void sendTxt(String sTxt) {
		byte[] bOutArray = sTxt.getBytes();
		send(bOutArray);
	}
	
	public void setReadWaitTime(int sReadWait){
		iReadWait = sReadWait;
	}

	// ----------------------------------------------------
	/**
	 * 
	 * zu se
	 *
	 */
/*	private class ReadThread extends Thread {
		@Override
		public void run() {
			super.run();
			while (!isInterrupted()) {
				try {
					try {
						if (mInputStream == null)
							return;
						byte[] combinBuffer = null;
						byte[] buffer = new byte[128];
						int size = mInputStream.read(buffer);
						Thread.sleep(25);
						if (size > 0) {
							combinBuffer = new byte[size];
							for (int i = 0; i < size; i++) {
								combinBuffer[i] = buffer[i];
							}
							while (mInputStream.available() > 0) {
								buffer = new byte[1024];
								int size2 = mInputStream.read(buffer);
								if (size2 > 0) {

									int oldSize = combinBuffer.length;
									byte[] combin = new byte[oldSize + size2];
									for (int i = 0; i < oldSize; i++) {
										combin[i] = combinBuffer[i];
									}
									for (int i = 0; i < size2; i++) {
										combin[oldSize + i] = buffer[i];
									}
									combinBuffer = combin;

									Thread.sleep(iReadWait);
								}
							}
							if (combinBuffer != null) {
								onDataReceived(combinBuffer);
							}
						}
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
						return;
					}
				} catch (Throwable e) {
					e.printStackTrace();
					return;
				}

			}
		}
	}
*/
	/**
	 * 
	 * fei zu se
	 *
	 */
	private class ReadThread extends Thread {
		@Override
		public void run() {
			super.run();
			if (mInputStream == null)
				return;
			while (!isInterrupted()) {
				try {
					try {
						byte[] buffer=new byte[128];
						int size = mInputStream.read(buffer);
						if (size > 0){
							SerialBean bean = new SerialBean(buffer, size);
							onDataReceived(bean);
						}
						sleep(1);
					} catch (IOException e) {
						e.printStackTrace();
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
					return;
				}
			}
		}
	}

	// ----------------------------------------------------
	private class SendThread extends Thread {
		public boolean suspendFlag = true;

		@Override
		public void run() {
			super.run();
			while (!isInterrupted()) {
				synchronized (this) {
					while (suspendFlag) {
						try {
							wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
							return;
						}
					}
				}
				send(getbLoopData());
				try {
					Thread.sleep(iDelay);
				} catch (InterruptedException e) {
					e.printStackTrace();
					return;
				}
				synchronized (this) {
					if (!isLoopChecked) {
						try {
							wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
							return;
						}
					}
				}
			}
		}

		public void setSuspendFlag() {
			this.suspendFlag = true;
		}

		public synchronized void setResume() {
			this.suspendFlag = false;
			notify();
		}
	}

	// ----------------------------------------------------
	public int getBaudRate() {
		return iBaudRate;
	}

	public boolean setBaudRate(int iBaud) {
		if (_isOpen) {
			return false;
		} else {
			iBaudRate = iBaud;
			return true;
		}
	}

	public boolean setBaudRate(String sBaud) {
		int iBaud = Integer.parseInt(sBaud);
		return setBaudRate(iBaud);
	}

	// ----------------------------------------------------
	public String getPort() {
		return sPort;
	}

	public boolean setPort(String sPort) {
		if (_isOpen) {
			return false;
		} else {
			this.sPort = sPort;
			return true;
		}
	}

	// ----------------------------------------------------
	public boolean isOpen() {
		return _isOpen;
	}

	// ----------------------------------------------------
	public byte[] getbLoopData() {
		return _bLoopData;
	}

	// ----------------------------------------------------
	public void setbLoopData(byte[] bLoopData) {
		this._bLoopData = bLoopData;
	}

	// ----------------------------------------------------
	public void setTxtLoopData(String sTxt) {
		this._bLoopData = sTxt.getBytes();
	}

	// ----------------------------------------------------
	public void setHexLoopData(String sHex) {
		this._bLoopData = MyFunc.HexToByteArr(sHex);
	}

	public void setLoopStatus(boolean checked) {
		isLoopChecked = checked;
	}

	public boolean getLoopStatus() {
		return isLoopChecked;
	}

	// ----------------------------------------------------
	public int getiDelay() {
		return iDelay;
	}

	// ----------------------------------------------------
	public void setiDelay(int iDelay) {
		this.iDelay = iDelay;
	}

	// ----------------------------------------------------
	public void startSend() {
		if (mSendThread != null && !TextUtils.isEmpty(new String(_bLoopData))) {
			mSendThread.setResume();
		}
	}

	// ----------------------------------------------------
	public void stopSend() {
		if (mSendThread != null) {
			mSendThread.setSuspendFlag();
		}
	}

	// ----------------------------------------------------
	protected abstract void onDataReceived(SerialBean bean);

	protected abstract void onDataSend(byte[] data);
}

/**
using example 
	private void initAndOpenSerial() {
		Log.d(TAG, "InitAndOpenSerial");
		if (sHelper != null && sHelper.isOpen())
			sHelper.close();
			
		if (sHelper == null) {
			sHelper = new SerialHelper(sPort, iBaudRate, true, false) {

				@Override
				protected void onDataReceived(byte[] data) {
					doSerialCallBack(data);
				}

				@Override
				protected void onDataSend(byte[] data) {
				}
			};
			sHelper.setiDelay(iDelay);
		}
		sHelper.setBaudRate(iBaudRate);
		sHelper.setOpt(databits, stopbits, parity);

		try {
			sHelper.open();
		} catch (SecurityException e) {
			Log.e(TAG, "open serial fial: no read/write permission");
		} catch (IOException e) {
			Log.e(TAG, "open serial fial, unknown error");
		} catch (InvalidParameterException e) {
			Log.e(TAG, "open serial fial, parameter error");
		}
	}
*/